<template>
  <div
    class="flex flex-col h-full"
    :class="{ 'heade-separate-table': headerSeparate, 'heade-merge-table': !headerSeparate }"
  >
    <div v-if="$slots.header" class="tn-table-header" :class="{ separate: headerSeparate }">
      <slot name="header"></slot>
    </div>
    <div
      class="flex-1 tn-table"
      :class="{
        pb0: !(tnTableProps.needToolbar || tnTableProps.needPagination),
        ['tn-table-' + tnTableProps.name]: true,
        'tn-data-table_full': isFull
      }"
    >
      <div class="tn-table-content" :class="{ 'tn-table-more-height': tnTableProps.moreHeight }">
        <vxe-table
          :key="tableKey"
          ref="tableRef"
          class="tn-table-main"
          :class="tnTableProps.stripe ? '' : 'nostripe'"
          :header-cell-class-name="headerCellClassName"
          :loading="dataLoading || loading"
          :align="allAlign"
          :column-config="{ resizable: true }"
          :height="tnTableProps.maxHeight && !isFull ? undefined : 'auto'"
          :max-height="isFull ? '' : tnTableProps.maxHeight"
          sync-resize="maxHeight"
          auto-resize
          :stripe="tnTableProps.stripe"
          :show-footer="!!tnTableProps.footerMethod"
          :data="handleTableData"
          :border="tnTableProps.bordered ? 'full' : 'none'"
          :scroll-y="{ enabled: tnTableProps.isVirtualScrolling, gt: 40 }"
          :scroll-x="{ enabled: false, gt: 0 }"
          show-header-overflow="title"
          :footer-method="tnTableProps.footerMethod"
          :row-config="{
            keyField: tnTableProps.rowKey,
            isHover: true
          }"
          :tree-config="
            isTreeTable
              ? {
                  transform: true,
                  parentField: 'parentId',
                  childrenField: tnTableProps.childrenColumnName,
                  rowField: tnTableProps.rowKey,
                  expandAll: tnTableProps.defaultExpandAllRows
                }
              : undefined
          "
          :checkbox-config="
            tnTableProps.rowSelection && tnTableProps.rowSelection.type !== 'radio'
              ? {
                  checkRowKeys: tnTableProps.rowSelection.selectedRowKeys,
                  checkMethod: ({ row }) => {
                    return tnTableProps.rowSelection.getCheckboxProps
                      ? !tnTableProps.rowSelection.getCheckboxProps(row).disabled
                      : true
                  },
                  visibleMethod: ({ row }) => {
                    return tnTableProps.rowSelection.renderCell ? !!tnTableProps.rowSelection.renderCell(row) : true
                  },
                  checkStrictly: tnTableProps.rowSelection.checkStrictly,
                  reserve: tnTableProps.rowSelection.preserveSelectedRowKeys
                }
              : undefined
          "
          :radio-config="
            tnTableProps.rowSelection && tnTableProps.rowSelection.type === 'radio'
              ? {
                  checkMethod: ({ row }) => {
                    return tnTableProps.rowSelection.getCheckboxProps
                      ? tnTableProps.rowSelection.getCheckboxProps(row).disabled
                      : true
                  },
                  trigger: 'row'
                }
              : undefined
          "
          :span-method="mergeRowMethod"
          :row-class-name="rowClassName"
          @checkbox-all="selectAllChangeEvent"
          @checkbox-change="selectChangeEvent"
          @radio-change="radioChangeEvent"
          @cell-click="cellClick"
          @resizable-change="resizableChange"
        >
          <vxe-column
            v-if="tnTableProps.rowSelection && tnTableProps.rowSelection.type !== 'radio'"
            type="checkbox"
            width="41"
            fixed="left"
            :show-header-overflow="'title'"
          ></vxe-column>
          <vxe-column
            v-if="tnTableProps.rowSelection && tnTableProps.rowSelection.type === 'radio'"
            type="radio"
            width="41"
            fixed="left"
          ></vxe-column>
          <vxe-column
            v-if="tnTableProps.showNo"
            title="序号"
            field="rowNo"
            width="60"
            fixed="left"
            align="left"
            :show-header-overflow="'title'"
            :tree-node="isTreeTable && tnTableProps.showNo ? !tnTableProps.expandIconColumnIndex : false"
          >
          </vxe-column>
          <template v-for="(item, index) in columns" :key="item.dataIndex">
            <vxe-colgroup
              v-if="item.children && item.children.length"
              :title="item.title"
              :min-width="item.minWidth"
              :align="item.align"
            >
              <vxe-column
                v-for="(child, i) in item.children"
                :key="child.dataIndex"
                :field="child.dataIndex"
                :title="child.title"
                :fixed="child.fixed"
                :visible="child.visible"
                :min-width="child.minWidth"
                :width="child.width"
                :show-overflow="child.hideTitle || child.dataIndex === 'edit' ? undefined : 'title'"
                :show-header-overflow="'title'"
                :align="child.align"
                :tree-node="isTreeNode(i)"
              >
                <template #header>
                  <slot name="headerCell" :column="child" :title="child.title"></slot>
                  <template v-if="!getSlotContent({ column: child }, 'headerCell')">
                    {{ child.title }}
                  </template>
                </template>
                <template #default="{ row, rowIndex }">
                  <slot name="bodyCell" :column="child" :record="row" :index="rowIndex"></slot>
                  <template v-if="!getSlotContent({ column: child, record: row, index: rowIndex }, 'bodyCell')">
                    {{
                      child.customRender
                        ? child.customRender({ record: row, index: rowIndex, text: row[child.dataIndex] })
                        : getVal(row, child.dataIndex) === 0
                        ? 0
                        : getVal(row, child.dataIndex) || '--'
                    }}
                  </template>
                </template>
              </vxe-column>
            </vxe-colgroup>
            <vxe-column
              v-else
              :field="item.dataIndex"
              :title="item.title"
              :fixed="item.fixed"
              :visible="item.visible"
              :min-width="item.minWidth"
              :width="item.width"
              :show-overflow="item.hideTitle || item.dataIndex === 'edit' ? undefined : 'title'"
              :show-header-overflow="'title'"
              :align="item.align"
              :tree-node="isTreeNode(index)"
            >
              <template #header>
                <slot name="headerCell" :column="item" :title="item.title"></slot>
                <template v-if="!getSlotContent({ column: item }, 'headerCell')">
                  {{ item.title }}
                </template>
              </template>
              <template #default="{ row, rowIndex }">
                <slot name="bodyCell" :column="item" :record="row" :index="rowIndex"></slot>
                <template v-if="!getSlotContent({ column: item, record: row, index: rowIndex }, 'bodyCell')">
                  {{
                    item.customRender
                      ? item.customRender({ record: row, index: rowIndex, text: row[item.dataIndex] })
                      : getVal(row, item.dataIndex) === 0
                      ? 0
                      : getVal(row, item.dataIndex) || '--'
                  }}
                </template>
              </template>
            </vxe-column>
          </template>
          <template #empty>
            <span style="color: #aeafb2">
              <img src="/src/assets/empty.png" width="80" />
              <p class="empty-text">暂无数据</p>
            </span>
          </template>
        </vxe-table>
      </div>
      <!-- 分页 -->
      <TnPage
        :pagination-config="paginationConfig"
        :need-pagination="tnTableProps.needPagination"
        :need-toolbar="tnTableProps.needToolbar"
        :table-name="tnTableProps.name"
        @page-change="pageChange"
        @show-config="showConfig"
        @fullFlagChange="fullFlagChange"
      ></TnPage>
      <!--列设置-->
      <ColumnConfig ref="refColumnConfig" @updateColumn="updateColumn" @restDefault="restDefault"></ColumnConfig>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, reactive, toRefs, useSlots, watch, nextTick, computed } from 'vue'
import type { VNode } from 'vue'
import { VxeTablePropTypes } from 'vxe-table'
import { VxeTableInstance, VxeTableEvents } from 'vxe-table'
import TnPage from './components/TnPage/index.vue'
import ColumnConfig from './components/ColumnConfig/index.vue'
import { IPage } from './type'
import { getUserConfig } from './config'

const uSlots = useSlots()

// const emptyImg = require('./assets/empty.png')

const getSlotContent = (data, slotName = 'bodyCell') => {
  if (uSlots?.[slotName]) {
    const result: VNode[] = uSlots[slotName]?.(data) || []
    return result.some((vNode) => {
      // 判断bodyCell插槽是否有内容，目前找到的规律就是插槽没有内容时，children是v-if，有内容时，children是插槽内容或者是数组
      if (vNode.children !== 'v-if') {
        return true
      }
      return false
    })
  }
  return false
}

const emits = defineEmits(['dataUpdate'])

const props = defineProps<{
  queryData?: any
  tnTableProps: any
  columns: any[]
  setTableDataFn?: Function
  headerSeparate?: boolean // 是否头部分离,
  loading?: boolean
  isVirtualScrolling?: boolean // 是否虚拟滚动
  stripe?: boolean // 是否斑马
}>()

// 合并参数 defaultTableOptions默认参数
const defaultTableOptions = {
  showNo: true, // 是否显示序号
  pagination: false, // 是否需要分页
  maxheight: 480, // 表格最大高度
  needPagination: true, // 是否需要分页
  needToolbar: true,
  initRequest: true, // 是否需要初始化请求
  isResizeWidth: true, // 是否支持拖动调整宽度
  isVirtualScrolling: true,
  stripe: true
}

const { queryData, tnTableProps: tableProps, columns, setTableDataFn } = toRefs(props)

const tnTableProps = computed(() => {
  return Object.assign({}, defaultTableOptions, tableProps.value)
})

const pageChange = ({ currentPage }) => {
  handleAsyncData(currentPage)
}

const allAlign = ref<VxeTablePropTypes.Align>(null)

// 表格全选
const tableRef = ref<VxeTableInstance<any>>()
const selectAllChangeEvent: VxeTableEvents.CheckboxAll<any> = () => {
  const $table = tableRef.value
  if ($table) {
    const records = $table
      .getCheckboxRecords()
      .filter((item) =>
        tnTableProps.value.rowSelection?.getCheckboxProps
          ? !tnTableProps.value.rowSelection.getCheckboxProps(item).disabled
          : true
      )
    const recordsReserve = $table
      .getCheckboxReserveRecords()
      .filter((item) =>
        tnTableProps.value.rowSelection?.getCheckboxProps
          ? !tnTableProps.value.rowSelection.getCheckboxProps(item).disabled
          : true
      )
    const recordKeys = tnTableProps.value.rowKey ? records.map((item) => item[tnTableProps.value.rowKey]) : []
    console.log(recordsReserve, records, '--recordKeys')
    const recordKeysReserve = tnTableProps.value.rowKey
      ? recordsReserve.map((item) => item[tnTableProps.value.rowKey])
      : []
    tnTableProps.value.rowSelection.onChange([...recordKeys, ...recordKeysReserve], [...records, ...recordsReserve])
  }
}

// 表格勾选
const selectChangeEvent: VxeTableEvents.CheckboxChange<any> = () => {
  const $table = tableRef.value
  if ($table) {
    const records = $table
      .getCheckboxRecords()
      .filter((item) =>
        tnTableProps.value.rowSelection?.getCheckboxProps
          ? !tnTableProps.value.rowSelection.getCheckboxProps(item).disabled
          : true
      )
    const recordsReserve = $table
      .getCheckboxReserveRecords()
      .filter((item) =>
        tnTableProps.value.rowSelection?.getCheckboxProps
          ? !tnTableProps.value.rowSelection.getCheckboxProps(item).disabled
          : true
      )
    const recordKeys = tnTableProps.value.rowKey ? records.map((item) => item[tnTableProps.value.rowKey]) : []
    const recordKeysReserve = tnTableProps.value.rowKey
      ? recordsReserve.map((item) => item[tnTableProps.value.rowKey])
      : []
    tnTableProps.value.rowSelection.onChange([...recordKeys, ...recordKeysReserve], [...records, ...recordsReserve])
  }
}

// 表格单选
const radioChangeEvent: VxeTableEvents.RadioChange<any> = ({ row }) => {
  const recordKeys = tnTableProps.value.rowKey ? [row].map((item) => item[tnTableProps.value.rowKey]) : []
  tnTableProps.value.rowSelection.onChange(recordKeys, row)
}

// 单元格点击
const cellClick = ({ row }) => {
  if (tnTableProps.value?.customRow) {
    tnTableProps.value.customRow(row).onClick()
  }
}

// 行样式设置
const rowClassName = ({ row, rowIndex }) => {
  return tnTableProps.value.rowClassName ? tnTableProps.value.rowClassName(row, rowIndex) : ''
}

// 合并单元格
const mergeRowMethod: any = ({ row, column }) => {
  const fields = getColumnMerge()
  if (fields.includes(column.property)) {
    const currItem = columns.value.find((item) => item.dataIndex === column.property)
    return {
      rowspan: currItem.customCell(row).rowSpan
    }
  }
  return { rowspan: 1 }
}

// 拖动改变列宽
const resizableChange = () => {
  const $table = tableRef.value
  if ($table) {
    const columns = $table?.getTableColumn().collectColumn
    refColumnConfig.value.saveColumn(columns, tnTableProps.value.name)
  }
}

// 获取需要合并的列
const getColumnMerge = () => {
  const needMergeColKeys: string[] = []
  columns.value.forEach((item: any) => {
    if (item.customCell) {
      needMergeColKeys.push(item.dataIndex)
    }
  })
  return needMergeColKeys
}

// 分页初始化
const paginationConfig = reactive<IPage>({
  currentPage: 1,
  pageSize: 12,
  total: 0,
  pageSizes: [12, 24, 48, 96]
})

// 获取用户配置
if (tnTableProps.value.name) {
  getUserConfig({ settingKey: tnTableProps.value.name })!.then((res) => {
    const columns = res.data?.settingJson?.columns
    if (columns && columns.length > 0) {
      const $table = tableRef.value
      const columns2 = $table?.getTableColumn().collectColumn
      const newColumns: any[] = []
      columns.forEach((el) => {
        const ele = columns2?.find((item) => item.field === el.field && item.type === el.type)
        if (ele) {
          ele.fixed = el.fixed
          ele.visible = el.visible
          ele.renderWidth = el.renderWidth
          ele.resizeWidth = el.resizeWidth
          newColumns.push(ele)
        }
      })
      // 新增的列在用户配置中找不到，就增加进去
      columns2?.forEach((el) => {
        const defaultColumnsItem = columns?.find((item) => item.field === el.field && item.type === el.type)
        if (!defaultColumnsItem) {
          newColumns.push(el)
        }
      })
      updateColumn(newColumns)
    }
  })
}

// 处理table的data数据
const handleTableData = ref<any[]>([])

// 处理异步数据
const dataLoading = ref(false)
const handleAsyncData = async (pageNum: number): Promise<void> => {
  const fn = tnTableProps.value.asyncApi || (() => Promise.resolve())
  dataLoading.value = true

  const res = await fn(
    Object.assign(
      {
        pageNum: paginationConfig.currentPage,
        pageSize: paginationConfig.pageSize
      },
      queryData?.value
    )
  ).catch(() => {
    dataLoading.value = false
  })

  dataLoading.value = false
  if (!res) {
    return
  }
  let list: any[] = []
  console.log(tnTableProps.value)
  if (tnTableProps.value.needPagination) {
    list = res.list || []
    paginationConfig.currentPage = pageNum
    paginationConfig.total = Number(res.total)
    // 这里来处理，实际只有10页，但是传入pageNum为11时，重置一下pageNum
    if (res.pages < res.pageNum && res.pages) {
      paginationConfig.currentPage = res.pages
      handleAsyncData(res.pages)
      return
    }
  } else {
    list = res || []
  }
  if (setTableDataFn?.value && typeof setTableDataFn.value === 'function') {
    list = setTableDataFn.value(list)
  }
  list = list.map((item: any, index: number) => {
    return {
      ...item,
      rowNo: (pageNum - 1) * paginationConfig.pageSize + index + 1
    }
  })
  // flattenTree(list || [])
  // handleTableData.value = list
  const tempArr = list
  handleTableData.value = flattenTree(list || [])

  if (tnTableProps.value.defaultExpandAllRows) {
    nextTick(() => {
      tableRef.value?.setAllTreeExpand(true)
    })
  }

  // 重新查询后，滚动条需要回到顶部
  nextTick(() => {
    setTimeout(() => {
      tableRef.value?.scrollTo(0, 0)
    }, 100)
  })

  // .vxe-table--body-wrapper
  emits('dataUpdate', {
    tableData: tempArr,
    queryData: queryData,
    paginationConfig: paginationConfig,
    checkedColumns: []
  })
  // tableRef.value?.loadData(tempArr).then(() => {
  // })
}

// 如果asyncApi存在，则请求数据
if (tnTableProps.value.asyncApi && tnTableProps.value.initRequest) {
  handleAsyncData(1)
}

// 处理树形表格
const isTreeTable = ref(false)
const flattenTree = (tree, parentId = null, result: any = [], temp: any = []) => {
  for (const node of tree) {
    const { [tnTableProps.value.childrenColumnName]: childList, ...rest } = node

    // 添加父级id字段
    const newNode = { ...rest, parentId }

    node.parentId = parentId
    delete node[tnTableProps.value.childrenColumnName]
    temp.push(node)

    // 将节点添加到结果数组中
    result.push(newNode)

    // 递归处理子级节点
    if (childList && childList.length > 0) {
      isTreeTable.value = true
      flattenTree(childList, node[tnTableProps.value.rowKey], result, temp)
    }
  }

  return temp
}

// 监听外部传入的数据，并加载进表格中
watch(
  () => tnTableProps.value.tableData,
  (newVal) => {
    // if (val) {
    //   flattenTree(val || [])
    //   handleTableData.value = val
    // }
    const val = (newVal || []).map((item: any, index: number) => {
      Object.assign(item, { rowNo: index + 1 })
      return item
    })
    handleTableData.value = flattenTree(val || [])
    nextTick(() => {
      if (tnTableProps.value.defaultExpandAllRows) {
        tableRef.value?.setAllRowExpand(true)
      }
      // const tempArr = flattenTree(val || [])
      // tableRef.value?.loadData(tempArr)
    })
  },
  {
    immediate: true
  }
)

// 判断当前节点是否为树形节点
const isTreeNode = (index) => {
  if (tnTableProps.value.expandIconColumnIndex || tnTableProps.value.expandIconColumnIndex === 0) {
    let defaultIndex = 0
    if (tnTableProps.value.rowSelection) {
      defaultIndex++
    }
    if (tnTableProps.value.showNo) {
      defaultIndex++
    }

    return index === tnTableProps.value.expandIconColumnIndex - defaultIndex
  }
  return false
}

/**
 * 动态获取多层级属性值
 * @param _obj 需要获取的对象（例：field: { options: rules: { type: 'string' } }）
 * @param field 字段名（例：field.options.rules.type）
 * @returns 值 （例：'string'）
 */
const getVal = (_obj, field) => {
  const arr = field.split('.')
  const str = arr[0]
  let temp = _obj[str]
  if (temp === undefined) {
    return undefined
  }
  if (field.indexOf('.') !== -1) {
    for (let i = 1; i < arr.length; i++) {
      if (i === arr.length - 1) {
        return temp[arr[i]]
      }
      if (temp[arr[i]] === undefined) {
        return undefined
      }
      temp = temp[arr[i]]
    }
  }

  return temp
}

// 刷新表格
const reloadTable = (pageNum?: number) => {
  handleAsyncData(pageNum || paginationConfig.currentPage)
}

// 增加表头自定义样式类
const headerCellClassName = () => {
  return 'custom-header-cell-class'
}

// 设置列
const refColumnConfig = ref()
const showConfig = () => {
  const $table = tableRef.value
  const columns = $table?.getTableColumn().collectColumn
  refColumnConfig.value?.showDraw(columns, tnTableProps.value.name)
}

// 更新列设置
const updateColumn = (columns) => {
  const $table = tableRef.value
  if ($table) {
    $table.loadColumn(columns)
    nextTick(() => {
      tableRef.value?.refreshColumn()
    })
  }
}

// 恢复默认设置
const tableKey = ref()
const restDefault = () => {
  const $table = tableRef.value
  if ($table) {
    $table
      .resetColumn({
        visible: true,
        resizable: true
      })
      .then(() => {
        tableKey.value = Math.random()
        nextTick(() => {
          const columns = tableRef.value?.getTableColumn().collectColumn
          refColumnConfig.value.saveColumn(columns, tnTableProps.value.name)
          refColumnConfig.value.closeDraw()
        })
      })
  }
}
// 手动清除checkbox的所有选中数据
const clearCheckChoose = () => {
  const $table = tableRef.value
  if ($table) {
    $table.clearCheckboxRow()
    $table.clearCheckboxReserve()
  }
}

// 全屏状态
const isFull = ref(false)
const fullFlagChange = (value) => {
  isFull.value = value
  tableKey.value = Math.random()
}
defineExpose({
  reloadTable,
  paginationConfig,
  clearCheckChoose
})
</script>
<style lang="less" scoped>
.tn-table-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #fff;
  width: 100%;
  padding: 8px 12px;
  min-height: 48px;
  height: auto;
  line-height: 1.5;
  &.separate {
    margin-bottom: 10px;
    border-radius: 8px;
  }
}
.tn-table {
  position: relative;
  padding-bottom: var(--vxe-table-row-height-default);
  height: 0px;
  display: flex;
  flex-direction: column;
  --vxe-primary-color: #1472ff;

  &.tn-data-table_full {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100%;
    z-index: 99;
  }
  :deep(.vxe-toolbar) {
    padding: 0;
    height: var(--vxe-table-row-height-default);
    line-height: var(--vxe-table-row-height-default);
  }

  .tn-table-content {
    flex: 1;
    overflow: hidden;

    .empty-text {
      line-height: 1;
      margin-bottom: 0;
    }
  }

  .tn-table-main {
    overflow: hidden;
    background-color: #fff;
    --vxe-table-row-hover-background-color: #e3eeff;
    --vxe-table-row-hover-striped-background-color: #e3eeff;
    // --vxe-table-body-background-color: #f5f8ff;
    --vxe-table-row-striped-background-color: #fff;
    :deep(.vxe-table--border-line) {
      border: none;
    }
  }
  :deep(.is--disabled) {
    .vxe-icon-checkbox-unchecked::before {
      content: '\e8d9';
    }
  }

  :deep(.vxe-table--header-wrapper) {
    color: #1f2123;
  }

  :deep(.custom-header-cell-class) {
    background: #fff;
    padding: 0;

    .vxe-resizable {
      right: -6px !important;
    }

    .vxe-resizable.is--line:before {
      height: 100%;
      background: linear-gradient(to bottom, #fff, #ededed);
    }
  }
  :deep(.custom-header-cell-class.col--group) {
    border-bottom: 1px solid #ededed;
  }

  :deep(.vxe-header--column) {
    .vxe-resizable.is--line:after,
    .vxe-resizable.is--line:before {
      vertical-align: top !important;
    }
  }

  // :deep(.vxe-table--render-default .vxe-body--row.row--stripe) {
  //   background-color: #fff !important;
  // }
  // :deep(.vxe-table--render-default .vxe-body--column.col--ellipsis) {
  //   background-color: inherit;
  // }
  :deep(.vxe-table--render-default .vxe-cell--checkbox .vxe-checkbox--icon) {
    font-weight: 400 !important;
  }
  :deep(.vxe-table--render-default .vxe-cell--radio .vxe-radio--icon) {
    font-weight: 400 !important;
  }
  :deep(.vxe-table--body-wrapper) {
    border-top: 1px solid #ededed;
  }
  // :deep(.vxe-table--main-wrapper .vxe-table--body-wrapper) {
  //   border-bottom: 1px solid #ededed;
  // }
}

.heade-separate-table {
  .tn-table {
    border-radius: 8px;
    overflow: hidden;
  }
}
.heade-merge-table {
  border-radius: 8px;
  overflow: hidden;
}

.tn-table-more-height {
  --vxe-table-row-height-default: 56px;
}
.pb0 {
  padding-bottom: 0;
}
:not(:root):fullscreen::backdrop {
  background: #f7f7f7;
}
</style>
